#ifndef DATASTRUCTS_H
#define DATASTRUCTS_H
#include "dxut/core/DXUT.h"
#include <string>
//--------------------------------------------------------------------------------------
//MARCO DEFINITION
//--------------------------------------------------------------------------------------
#define  EPSILON  0.000001
#define  NDFPLOTSCALE 1000
#define  DEGREE2RADIAN (D3DX_PI/180.0)
#define  RADIAN2DEGREE (180.0/D3DX_PI)
//--------------------------------------------------------------------------------------
//D3D Utility Functions
//--------------------------------------------------------------------------------------
struct RGBA8Bytes
{
	BYTE r;
	BYTE g;
	BYTE b;
	BYTE a;

	RGBA8Bytes()
	{
		r = 0; g = 0; b = 0; a = 0;		
	}

	RGBA8Bytes(BYTE r1, BYTE g1, BYTE b1, BYTE a1)
	{
		r = r1; g = g1; b = b1; a = a1;
	}

	RGBA8Bytes(const RGBA8Bytes&  rgba)
	{
		r = rgba.r; g = rgba.g; b = rgba.b; a = rgba.a;
	}
};

struct VertexType_POS
{
	D3DXVECTOR3 Pos;
};

struct VertexType_POSNORM
{
	D3DXVECTOR3 pos;
	D3DXVECTOR3 norm;
};

struct ScreenVertex2DTex
{
	D3DXVECTOR3 pos_proj;
	D3DXVECTOR2 uv;
};


struct PT_VertColor
{
	D3DXVECTOR3 pos;
	D3DXVECTOR4 color;

	PT_VertColor()
	{
		pos = D3DXVECTOR3(0,0,0);
		color = D3DXVECTOR4(0,0,0,0);		
	}
	~PT_VertColor(){}
	//Constructor
	PT_VertColor(const D3DXVECTOR3& pos, const D3DXVECTOR4& color)
	{
		this->pos = pos;
		this->color = color;
	}

	PT_VertColor(const PT_VertColor& pt)
	{
		pos = pt.pos;
		color = pt.color;
	}
};

//--------------------------------------------------------------------------------------
//Gonio File IO
//--------------------------------------------------------------------------------------
struct AngleMappingData
{
	float fThetaIn;
	float fPhiIn;
	float fThetaOut;
	float fPhiOut;
	int   iDeviceIncident;
	int   iDeviceDetect;
	int   iFlop;

	AngleMappingData()
	{
		memset(this,0,sizeof(*this));
	}
};

struct PCGGonioMeasuredData
{
	float m_fThetaIn;
	float m_fThetaOut;
	float m_fBRDF;

	PCGGonioMeasuredData():m_fThetaIn(0),m_fThetaOut(0),m_fBRDF(0)
	{

	}
};

struct GonioMeasuredData
{
	std::string sSampleName;
	std::string sComment;
	std::string sBelongToName;
	std::string sDate;
	std::string sTime;
	float fRotateAngle;//measure sample rotation!!!
	int   iDeviceIncident;
	int   iDeviceDetect;
	float fFlappingAngle;
	float fSurfaceRotatingAngle;
	float RfRadiance390nm;
	float RfRadiance400nm;
	float RfRadiance410nm;
	float RfRadiance420nm;
	float RfRadiance430nm;
	float RfRadiance440nm;
	float RfRadiance450nm;
	float RfRadiance460nm;
	float RfRadiance470nm;
	float RfRadiance480nm;
	float RfRadiance490nm;
	float RfRadiance500nm;
	float RfRadiance510nm;
	float RfRadiance520nm;
	float RfRadiance530nm;
	float RfRadiance540nm;
	float RfRadiance550nm;
	float RfRadiance560nm;
	float RfRadiance570nm;
	float RfRadiance580nm;
	float RfRadiance590nm;
	float RfRadiance600nm;
	float RfRadiance610nm;
	float RfRadiance620nm;
	float RfRadiance630nm;
	float RfRadiance640nm;
	float RfRadiance650nm;
	float RfRadiance660nm;
	float RfRadiance670nm;
	float RfRadiance680nm;
	float RfRadiance690nm;
	float RfRadiance700nm;
	float RfRadiance710nm;
	float RfRadiance720nm;
	float RfRadiance730nm;

	GonioMeasuredData()
	{
		iDeviceIncident = 0;
		iDeviceDetect = 0;
		fFlappingAngle = 0;
		fSurfaceRotatingAngle = 0;
		fRotateAngle = 0;
		RfRadiance390nm = 0;
		RfRadiance400nm = 0;
		RfRadiance410nm = 0;
		RfRadiance420nm = 0;
		RfRadiance430nm = 0;
		RfRadiance440nm = 0;
		RfRadiance450nm = 0;
		RfRadiance460nm = 0;
		RfRadiance470nm = 0;
		RfRadiance480nm = 0;
		RfRadiance490nm = 0;
		RfRadiance500nm = 0;
		RfRadiance510nm = 0;
		RfRadiance520nm = 0;
		RfRadiance530nm = 0;
		RfRadiance540nm = 0;
		RfRadiance550nm = 0;
		RfRadiance560nm = 0;
		RfRadiance570nm = 0;
		RfRadiance580nm = 0;
		RfRadiance590nm = 0;
		RfRadiance600nm = 0;
		RfRadiance610nm = 0;
		RfRadiance620nm = 0;
		RfRadiance630nm = 0;
		RfRadiance640nm = 0;
		RfRadiance650nm = 0;
		RfRadiance660nm = 0;
		RfRadiance670nm = 0;
		RfRadiance680nm = 0;
		RfRadiance690nm = 0;
		RfRadiance700nm = 0;
		RfRadiance710nm = 0;
		RfRadiance720nm = 0;
		RfRadiance730nm = 0;
	}

};

struct NDFCountElem
{
	unsigned int iCount;
	float fVal;
	float fAngles;//degrees

	NDFCountElem()
	{
		iCount = 0;
		fVal = 0;
		fAngles = 0;
	}
};

struct NDFItem
{
	int iAngleIdx;
	double AngleThetaM;
	double NDFVal;

	NDFItem()
	{
		iAngleIdx = -1;
		AngleThetaM = 0;
		NDFVal = 0;
	}
};

enum METALTYPE
{
	STAINLESS = 0,
	ALUMINUM,
	COPPER,
};

struct WaveOpticBRDF
{
	D3DXVECTOR3 vHalf_UnNorm;
	float m_fThetaM;
	double BRDFVal;

	WaveOpticBRDF():vHalf_UnNorm(0,0,0), m_fThetaM(0.0f), BRDFVal(0)
	{}
};

struct LineSeg2D
{
	D3DXVECTOR2 vStartPt;
	D3DXVECTOR2 vEndPt;
	D3DXVECTOR2 vNorm2D;
	
	LineSeg2D():vStartPt(0,0),vEndPt(0,0),vNorm2D(0,0) {}
    inline void computeNorm2D()
	{
		float dx = vEndPt.x - vStartPt.x;
		float dy = vEndPt.y - vStartPt.y;
		D3DXVECTOR2 vTmp;
		if(dx > 0)
			vTmp = D3DXVECTOR2(-dy,dx);
		else
			vTmp = D3DXVECTOR2(dy,-dx);
		//normalization
		D3DXVec2Normalize(&vNorm2D,&vTmp);
	}
};


class Ray2D {
public:
	//we store parametric values tStart and tEnd in otherwise unused fourth components of origin and direction
	D3DXVECTOR2 origin;
	D3DXVECTOR2 direction;
	float tStart, tEnd;

	float originX() const { return origin[0]; }
	float &originX() { return origin[0]; }
	float originY() const { return origin[1]; }
	float &originY() { return origin[1]; }
	float dirX() const { return direction[0]; }
	float &dirX() { return direction[0]; }
	float dirY() const { return direction[1]; }
	float &dirY() { return direction[1]; }
	void setOrigin(float x, float y) { origin = D3DXVECTOR2(x,y); }
	void setDirection(float x, float y) { direction = D3DXVECTOR2(x,y); }
	void setTParameters(float start, float end) { tStart = start; tEnd = end; }
	void setAsSegment(float startX, float startY, float endX, float endY) { 
		origin = D3DXVECTOR2(startX, startY);
		direction = D3DXVECTOR2(endX-startX,endY-startY);
		tStart = 0; tEnd = 1.0f;
	}
	void setAsSegment(const D3DXVECTOR2 &start, const D3DXVECTOR2 &end) {
		origin = start;
		direction = end-start;
		tStart = 0; tEnd = 1.0f;
	}
	D3DXVECTOR2 getStartPoint() {
		return origin + tStart*direction;
	}
	D3DXVECTOR2 getEndPoint() {
		return origin + tEnd*direction;
	}
	D3DXVECTOR2 getTValuePoint(float tValue) {
		return origin + tValue*direction;
	}
};


class IntersectionRecord2D {
public:
	int primitiveId;
	float fLength; //along ray
	IntersectionRecord2D():primitiveId(-1),fLength(-1.0f) {}
};

#endif